package com.jagochan.imchat.module.common.utils.redissonlock;

import cn.hutool.core.util.StrUtil;
import com.jagochan.imchat.module.common.utils.SpElUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Order(0) // 保证该切面在@Transactional之前执行
public class RedissonLockAspect {

    @Autowired
    private RedissonLockService redissonLockService;

    @Around("@annotation(enableRedissonLock)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, EnableRedissonLock enableRedissonLock) throws Throwable {
        // 获取方法对象
        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();

        String key = getRedisKey(method, proceedingJoinPoint.getArgs(), enableRedissonLock);
        long waitTime = enableRedissonLock.waitTime();
        TimeUnit timeUnit = enableRedissonLock.timeUnit();

        return redissonLockService.executeWithLockThrows(key, waitTime, timeUnit, proceedingJoinPoint::proceed);
    }

    private String getRedisKey(Method method, Object[] args, EnableRedissonLock enableRedissonLock) {
        String prefixKey = enableRedissonLock.prefixKey();
        String key = SpElUtil.parseSpElKey(method, args, enableRedissonLock.key());

        if (StrUtil.isBlank(prefixKey)) {
            prefixKey = SpElUtil.getMethodFullName(method);
        }

        return prefixKey + ":" + key;
    }

}
